
from time import sleep
import smbus
# 各寄存器地址定义
REG_INTR_STATUS_1 = 0x00
REG_INTR_STATUS_2 = 0x01

REG_INTR_ENABLE_1 = 0x02
REG_INTR_ENABLE_2 = 0x03

REG_FIFO_WR_PTR = 0x04
REG_OVF_COUNTER = 0x05
REG_FIFO_RD_PTR = 0x06
REG_FIFO_DATA = 0x07
REG_FIFO_CONFIG = 0x08

REG_MODE_CONFIG = 0x09
REG_SPO2_CONFIG = 0x0A
REG_LED1_PA = 0x0C

REG_LED2_PA = 0x0D
REG_PILOT_PA = 0x10
REG_MULTI_LED_CTRL1 = 0x11
REG_MULTI_LED_CTRL2 = 0x12

REG_TEMP_INTR = 0x1F
REG_TEMP_FRAC = 0x20
REG_TEMP_CONFIG = 0x21
REG_PROX_INT_THRESH = 0x30
REG_REV_ID = 0xFE
REG_PART_ID = 0xFF


class MAX30102():
    # 1通道、地址57的I2C初始化
    def __init__(self, channel=1, address=0x57):
        # I2C初始化定义I2C控制对象
        self.address = address
        self.channel = channel
        self.bus = smbus.SMBus(self.channel)
        
        # 芯片复位
        self.reset()#复位函数
        sleep(1)  #等待1秒

        # 读取中断状态
        reg_data = self.bus.read_i2c_block_data(self.address, REG_INTR_STATUS_1, 1) #REG_INTR_STATUS_1这个寄存器读取中断状态
        print("reset state",reg_data)
        
        # 进行初始化
        self.setup()
       
    def shutdown(self):
        """
        设备关闭
        """
        self.bus.write_i2c_block_data(self.address, REG_MODE_CONFIG, [0x80])#1000 0000 关闭

    def reset(self):
        """
        芯片复位
        """
        self.bus.write_i2c_block_data(self.address, REG_MODE_CONFIG, [0x40]) #0100 0000

    def setup(self, led_mode=0x03):
        """
        芯片设置
        """
        # 中断设置
        self.bus.write_i2c_block_data(self.address, REG_INTR_ENABLE_1, [0xc0]) #中断使能寄存器1 1100 0000寄存器快满、新数据准备好，发送中断。后面未用到
        self.bus.write_i2c_block_data(self.address, REG_INTR_ENABLE_2, [0x00])
        #初始时，读写指针均置为0
        # FIFO写指针
        self.bus.write_i2c_block_data(self.address, REG_FIFO_WR_PTR, [0x00])
        # OVF_COUNTER[4:0]
        self.bus.write_i2c_block_data(self.address, REG_OVF_COUNTER, [0x00])
        # FIFO_读指针
        self.bus.write_i2c_block_data(self.address, REG_FIFO_RD_PTR, [0x00])

        # FIFO configuration 4位取平均，缓存满了不覆盖，满15样本后发送中断标志
        self.bus.write_i2c_block_data(self.address, REG_FIFO_CONFIG, [0x4f])#0100 1111 
        # 心率血氧测量模式led_mode=0x03
        self.bus.write_i2c_block_data(self.address, REG_MODE_CONFIG, [led_mode])
        # SpO2 configuration 0010 0111 量程4096,采样率100,精度18bit/脉宽411μS
        self.bus.write_i2c_block_data(self.address, REG_SPO2_CONFIG, [0x27])

        # LED1驱动电流7mA
        self.bus.write_i2c_block_data(self.address, REG_LED1_PA, [0x24])
        # LED2驱动电流7mA
        self.bus.write_i2c_block_data(self.address, REG_LED2_PA, [0x24])
        # Pilot LED驱动电流25mA
        self.bus.write_i2c_block_data(self.address, REG_PILOT_PA, [0x7f])

    # this won't validate the arguments!
    # use when changing the values from default
    def set_config(self, reg, value):
        self.bus.write_i2c_block_data(self.address, reg, value)
    # 得到当前缓冲区中样本的数量
    def get_data_present(self):
        #读指针位置
        read_ptr = self.bus.read_byte_data(self.address, REG_FIFO_RD_PTR)
        #写指针位置
        write_ptr = self.bus.read_byte_data(self.address, REG_FIFO_WR_PTR)
        if read_ptr == write_ptr:
            #位置相等无数据
            return 0
        else:
            num_samples = write_ptr - read_ptr
            # 如果读指针位置小于写指针，表示写过一轮，从头再写，则需要加上32的缓冲区长度
            if num_samples < 0:
                num_samples += 32
            return num_samples

    def read_fifo(self):
        """
        从数据寄存器中读取一个样本.
        """
        red_led = None
        ir_led = None

        # 读一下中断状态（未用到）
        reg_INTR1 = self.bus.read_i2c_block_data(self.address, REG_INTR_STATUS_1, 1)
        reg_INTR2 = self.bus.read_i2c_block_data(self.address, REG_INTR_STATUS_2, 1)

        # 从设备中读取6个字节
        d = self.bus.read_i2c_block_data(self.address, REG_FIFO_DATA, 6)

        # mask MSB [23:18]
        red_led = (d[0] << 16 | d[1] << 8 | d[2]) & 0x03FFFF
        ir_led = (d[3] << 16 | d[4] << 8 | d[5]) & 0x03FFFF

        return red_led, ir_led

    def read_sequential(self, amount=100):
        """
        This function will read the red-led and ir-led `amount` times.
        This works as blocking function.
        """
        red_buf = []
        ir_buf = []
        count = amount
        while count > 0:
            num_bytes = self.get_data_present()
            while num_bytes > 0:
                red, ir = self.read_fifo()

                red_buf.append(red)
                ir_buf.append(ir)
                num_bytes -= 1
                count -= 1

        return red_buf, ir_buf
        
        

    
    
    

if __name__ == "__main__":
    
    import numpy as np
    #import cv2
    buff_size = 100
   
    
    # 定义传感器
    sensor = MAX30102()
    flag_finger = False
    ir_data = []
    red_data = []
    
    try:
        while True:
            
            # 获得FIFO中的样本数目
            num_bytes = sensor.get_data_present()
            if num_bytes > 0:
                # 依次读取数据   
                while num_bytes > 0:
                    red, ir = sensor.read_fifo()
                    num_bytes -= 1
                    ir_data.append(ir)
                    red_data.append(red)
                    # print("ir: %d  red :%d"%(ir,red))
                    
                    # 大于100个样本则删除开头的样本
                    while len(ir_data) > buff_size:
                        ir_data.pop(0)
                        red_data.pop(0)
                        print("ir")
                    if len(ir_data) == buff_size:
                        if (np.mean(ir_data) < 50000 and np.mean(red_data) < 50000):
                            flag_finger = False
                        else:
                            flag_finger = True
                            
            sleep(0.01)
            if not flag_finger:
                print("flag_finger not find")

    except KeyboardInterrupt:
        print("KeyboardInterrupt")
                
            



